#include "quadtreeindex.h"

quadTreeIndex::quadTreeIndex()
{
    type=QUADTREE;
}

quadTreeIndex::~quadTreeIndex()
{

}

bool quadTreeIndex::initialize(double minX, double maxX, double minY, double maxY,geoMap*map1)
{
    this->map=map1;
    cellForIndex* rootCell=new cellForIndex();
    rootCell->minX=minX;
    rootCell->minY=minY;
    rootCell->maxX=maxX;
    rootCell->maxY=maxY;
    splitCell(rootCell);
    cells.append(rootCell);
    isInitialized=true;
    return true;
}

QVector<cellForIndex*> quadTreeIndex::getPaintCells()
{
    return cells;
}

void quadTreeIndex::splitCell(cellForIndex *cell)
{
    if(cell==nullptr)   return;
    if(getSumWithinObjects(cell)>3)
    {
        for(int i=0;i<4;i++)
        {
            cellForIndex*child=new cellForIndex();
            cell->addChildCell(child);
        }
        cell->getChildCell(0)->minX=cell->minX;
        cell->getChildCell(0)->maxX=cell->getChildCell(0)->minX+(cell->maxX-cell->minX)/2;
        cell->getChildCell(0)->minY=cell->minY;
        cell->getChildCell(0)->maxY=cell->getChildCell(0)->minY+(cell->maxY-cell->minY)/2;

        cell->getChildCell(1)->minX=(cell->maxX-cell->minX)/2+cell->minX;
        cell->getChildCell(1)->maxX=cell->getChildCell(1)->minX+(cell->maxX-cell->minX)/2;
        cell->getChildCell(1)->minY=(cell->maxY-cell->minY)/2+cell->minY;
        cell->getChildCell(1)->maxY=cell->getChildCell(1)->minY+(cell->maxY-cell->minY)/2;

        cell->getChildCell(2)->minX=(cell->maxX-cell->minX)/2+cell->minX;
        cell->getChildCell(2)->maxX=cell->getChildCell(2)->minX+(cell->maxX-cell->minX)/2;
        cell->getChildCell(2)->minY=cell->minY;
        cell->getChildCell(2)->maxY=cell->getChildCell(2)->minY+(cell->maxY-cell->minY)/2;

        cell->getChildCell(3)->minX=cell->minX;
        cell->getChildCell(3)->maxX=cell->getChildCell(3)->minX+(cell->maxX-cell->minX)/2;
        cell->getChildCell(3)->minY=(cell->maxY-cell->minY)/2+cell->minY;
        cell->getChildCell(3)->maxY=cell->getChildCell(1)->minY+(cell->maxY-cell->minY)/2;

        for(int i=0;i<4;i++)
        {
            cells.append(cell->getChildCell(i));
            splitCell(cell->getChildCell(i));
        }
    }
    else return;
}

int quadTreeIndex::getSumWithinObjects(cellForIndex* cell)
{
    int sum=0;
    QVector<geoObject*>objects;
    foreach(geoLayer*layer,map->geoLayers)
    {
        foreach(geoObject*object,layer->geoObjects)
        {
            if(object->type=="MultiPolygon")
            {
                foreach(geoPolygon*polygon,dynamic_cast<geoMultiPolygon*>(object)->polygons)
                {
                    bool counted=false;
                    foreach(QPointF coordinate,polygon->projectedCoordinates)
                    {
                        if(cell->isPointWithin(coordinate))
                        {
                            sum++;
                            counted=true;
                            break;
                        }
                    }
                    if(counted==true)
                    {
                        objects.append(object);
                        break;
                    }
                }
            }
            else if(object->type=="MultiLinString")
            {
                foreach(geoLineString* lineString,dynamic_cast<geoMultiLineString*>(object)->lineStrings)
                {
                    bool counted=false;
                    foreach(QPointF coordinate,lineString->projectedCoordinates)
                    {
                        if(cell->isPointWithin(coordinate))
                        {
                            sum++;
                            counted=true;
                            break;
                        }
                        if(counted==true)
                        {
                            objects.append(object);
                            break;
                        }
                    }
                }
            }
            else
            {
                foreach(QPointF coordinate,object->projectedCoordinates)
                {
                    if(cell->isPointWithin(coordinate))
                    {
                        sum++;
                        break;
                    }
                }
                objects.append(object);
            }
        }
    }

    if(sum<=3)
    {
        leafCells.append(cell);
        cell->setObjectsWithin(objects);
    }
    return sum;
}
